{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Benchmark of Element Wise Matrix Multiplications\n",
    "On this benchmark we compare several operations using numpy, numexpr, numba (CPU&GPU) and PyTorch GPU."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "System version: 3.6.7 |Anaconda, Inc.| (default, Oct 23 2018, 19:16:44) \n",
      "[GCC 7.3.0]\n",
      "Numpy version: 1.16.0\n",
      "Pandas version: 0.23.4\n",
      "Numexpr version: 2.6.9\n",
      "PyTorch version: 1.0.0\n",
      "BLAS info:\n",
      "blas_mkl_info:\n",
      "  NOT AVAILABLE\n",
      "blis_info:\n",
      "  NOT AVAILABLE\n",
      "openblas_info:\n",
      "    libraries = ['openblas', 'openblas']\n",
      "    library_dirs = ['/usr/local/lib']\n",
      "    language = c\n",
      "    define_macros = [('HAVE_CBLAS', None)]\n",
      "blas_opt_info:\n",
      "    libraries = ['openblas', 'openblas']\n",
      "    library_dirs = ['/usr/local/lib']\n",
      "    language = c\n",
      "    define_macros = [('HAVE_CBLAS', None)]\n",
      "lapack_mkl_info:\n",
      "  NOT AVAILABLE\n",
      "openblas_lapack_info:\n",
      "    libraries = ['openblas', 'openblas']\n",
      "    library_dirs = ['/usr/local/lib']\n",
      "    language = c\n",
      "    define_macros = [('HAVE_CBLAS', None)]\n",
      "lapack_opt_info:\n",
      "    libraries = ['openblas', 'openblas']\n",
      "    library_dirs = ['/usr/local/lib']\n",
      "    language = c\n",
      "    define_macros = [('HAVE_CBLAS', None)]\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "import os\n",
    "import numpy as np\n",
    "import numexpr as ne\n",
    "from numba import vectorize\n",
    "from numba.cuda.cudadrv.error import CudaDriverError\n",
    "import math\n",
    "from functools import reduce\n",
    "import pandas as pd\n",
    "import torch\n",
    "from utils import (get_number_processors, get_ram_memory, get_total_gpu_memory, \n",
    "                   get_gpu_name, get_cuda_version, get_cudnn_version, AttributeDict,\n",
    "                   get_object_size, clear_memory_all_gpus)\n",
    "\n",
    "print(\"System version: {}\".format(sys.version))\n",
    "print(\"Numpy version: {}\".format(np.__version__))\n",
    "print(\"Pandas version: {}\".format(pd.__version__))\n",
    "print(\"Numexpr version: {}\".format(ne.__version__))\n",
    "print(\"PyTorch version: {}\".format(torch.__version__))\n",
    "print(\"BLAS info:\") \n",
    "print(np.show_config())\n",
    "\n",
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Helper functions for numpy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def multiply(a,b):\n",
    "    return a*b\n",
    "\n",
    "def exponential(a, b):\n",
    "    return a*np.exp(b)\n",
    "\n",
    "def sine(a, b):\n",
    "    return a*np.sin(b)\n",
    "\n",
    "# A general function that multiplies an arbitrary number of matrices\n",
    "# is 28% slower than directly multiplying the factors.\n",
    "# The function multiply_list is not used, just leaving it here for reference\n",
    "def multiply_list(l):\n",
    "    return reduce(lambda x, y: x*y, l) \n",
    "\n",
    "def multiply3(a, b, c):\n",
    "    return a*b*c\n",
    "\n",
    "def multiply5(a, b, c, d, e):\n",
    "    return a*b*c*d*e\n",
    "\n",
    "def exponential_sine(a, b, c):\n",
    "    return a*np.exp(b)*np.sin(c)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Helper functions for numexpr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def ne_multiply(a,b):\n",
    "    return ne.evaluate(\"a*b\")\n",
    "\n",
    "def ne_exponential(a, b):\n",
    "    return ne.evaluate(\"a*exp(b)\")\n",
    "\n",
    "def ne_sine(a, b):\n",
    "    return ne.evaluate(\"a*sin(b)\")\n",
    "\n",
    "def ne_multiply3(a, b, c):\n",
    "    return ne.evaluate(\"a*b*c\")\n",
    "\n",
    "def ne_multiply5(a, b, c, d, e):\n",
    "    return ne.evaluate(\"a*b*c*d*e\")\n",
    "\n",
    "def ne_exponential_sine(a, b, c):\n",
    "    return ne.evaluate(\"a*exp(b)*sin(c)\")\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Helper functions for numba\n",
    "NOTE: For numba solutions, having a solution empty vector speeds up around 10%\n",
    "```\n",
    "r0 = np.empty((S1, S2), dtype=np.int16)\n",
    "r0 = multicpu(a, b)\n",
    "```\n",
    "source: https://devblogs.nvidia.com/numba-python-cuda-acceleration/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "@vectorize([\"int16(int16, int16)\",\"float32(float32, float32)\"], target=\"cpu\")\n",
    "def multcpu(a, b):\n",
    "    return a * b\n",
    "\n",
    "@vectorize([\"int16(int16, int16)\",\"float32(float32, float32)\"], target=\"parallel\")\n",
    "def multparal(a, b):\n",
    "    return a * b\n",
    "\n",
    "@vectorize([\"int16(int16, int16)\",\"float32(float32, float32)\"], target=\"cuda\")\n",
    "def multcuda(a, b):\n",
    "    return a * b\n",
    "\n",
    "@vectorize([\"float32(float32, float32)\"], target=\"cpu\")\n",
    "def expcpu(a, b):\n",
    "    return a*math.exp(b)\n",
    "\n",
    "@vectorize([\"float32(float32, float32)\"], target=\"parallel\")\n",
    "def expparal(a, b):\n",
    "    return a*math.exp(b)\n",
    "\n",
    "@vectorize([\"float32(float32, float32)\"], target=\"cuda\")\n",
    "def expcuda(a, b):\n",
    "    return a*math.exp(b)\n",
    "\n",
    "@vectorize([\"float32(float32, float32)\"], target=\"cpu\")\n",
    "def sincpu(a, b):\n",
    "    return a*math.sin(b)\n",
    "\n",
    "@vectorize([\"float32(float32, float32)\"], target=\"parallel\")\n",
    "def sinparal(a, b):\n",
    "    return a*math.sin(b)\n",
    "\n",
    "@vectorize([\"float32(float32, float32)\"], target=\"cuda\")\n",
    "def sincuda(a, b):\n",
    "    return a*math.sin(b)\n",
    "\n",
    "@vectorize([\"float32(float32, float32, float32)\"], target=\"cpu\")\n",
    "def multfcpu3(a, b, c):\n",
    "    return a * b * c\n",
    "\n",
    "@vectorize([\"float32(float32, float32, float32)\"], target=\"parallel\")\n",
    "def multfparal3(a, b, c):\n",
    "    return a * b * c\n",
    "\n",
    "@vectorize([\"float32(float32, float32, float32)\"], target=\"cuda\")\n",
    "def multfcuda3(a, b, c):\n",
    "    return a * b * c\n",
    "\n",
    "@vectorize([\"float32(float32, float32, float32, float32, float32)\"], target=\"cpu\")\n",
    "def multfcpu5(a, b, c, d, e):\n",
    "    return a * b * c * d * e\n",
    "\n",
    "@vectorize([\"float32(float32, float32, float32, float32, float32)\"], target=\"parallel\")\n",
    "def multfparal5(a, b, c, d, e):\n",
    "    return a * b * c * d * e\n",
    "\n",
    "@vectorize([\"float32(float32, float32, float32, float32, float32)\"], target=\"cuda\")\n",
    "def multfcuda5(a, b, c, d, e):\n",
    "    return a * b * c * d * e\n",
    "\n",
    "@vectorize([\"float32(float32, float32, float32)\"], target=\"cpu\")\n",
    "def expsincpu(a, b, c):\n",
    "    return a*math.exp(b)*math.sin(c)\n",
    "\n",
    "@vectorize([\"float32(float32, float32, float32)\"], target=\"parallel\")\n",
    "def expsinparal(a, b, c):\n",
    "    return a*math.exp(b)*math.sin(c)\n",
    "\n",
    "@vectorize([\"float32(float32, float32, float32)\"], target=\"cuda\")\n",
    "def expsincuda(a, b, c):\n",
    "    return a*math.exp(b)*math.sin(c)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Helper functions for PyTorch\n",
    "\n",
    "*Note on performance*: \n",
    "\n",
    "`torch.as_tensor(a)` does not make a copy of a on CPU. Adding `.cuda()` copies the array to GPU memory.\n",
    "\n",
    "More info: https://pytorch.org/docs/stable/tensors.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def pt_multiply(a,b):\n",
    "    at = torch.as_tensor(a).cuda() \n",
    "    bt = torch.as_tensor(b).cuda()\n",
    "    return at*bt\n",
    "\n",
    "def pt_exponential(a, b):\n",
    "    at = torch.as_tensor(a).cuda() \n",
    "    bt = torch.as_tensor(b).cuda()\n",
    "    return at*torch.exp(bt)\n",
    "\n",
    "def pt_sine(a, b):\n",
    "    at = torch.as_tensor(a).cuda() \n",
    "    bt = torch.as_tensor(b).cuda()\n",
    "    return at*torch.sin(bt)\n",
    "\n",
    "def pt_multiply3(a, b, c):\n",
    "    at = torch.as_tensor(a).cuda() \n",
    "    bt = torch.as_tensor(b).cuda()\n",
    "    ct = torch.as_tensor(c).cuda()\n",
    "    return at*bt*ct\n",
    "\n",
    "def pt_multiply5(a, b, c, d, e):\n",
    "    at = torch.as_tensor(a).cuda() \n",
    "    bt = torch.as_tensor(b).cuda()\n",
    "    ct = torch.as_tensor(c).cuda()\n",
    "    dt = torch.as_tensor(d).cuda()\n",
    "    et = torch.as_tensor(e).cuda()\n",
    "    return at*bt*ct*dt*et\n",
    "\n",
    "def pt_exponential_sine(a, b, c):\n",
    "    at = torch.as_tensor(a).cuda() \n",
    "    bt = torch.as_tensor(b).cuda()\n",
    "    ct = torch.as_tensor(c).cuda()\n",
    "    return at*torch.exp(bt)*torch.sin(ct)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "size_combinations=[\n",
    "    (100, 100),\n",
    "    (1000, 1000),\n",
    "    (10000, 10000),\n",
    "    (100000, 10000),\n",
    "    (100000, 100000)\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "columns = [\"n_processors\",\n",
    "           \"cpu_memory\",\n",
    "           \"gpu_name\",\n",
    "           \"gpu_memory\",\n",
    "           \"data_type\",\n",
    "           \"size1\",\n",
    "           \"size2\",\n",
    "           \"operation\",\n",
    "           \"numpy\",\n",
    "           \"numexpr\",\n",
    "           \"numba_cpu\",\n",
    "           \"numba_paral\",\n",
    "           \"numba_gpu\",\n",
    "           \"pytorch\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "n_processors = get_number_processors()\n",
    "cpu_memory = get_ram_memory(units=\"Gb\")\n",
    "gpu_name = get_gpu_name()[0]\n",
    "gpu_memory = get_total_gpu_memory(units=\"Gb\")[0]\n",
    "header = [n_processors, cpu_memory, gpu_name, gpu_memory]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Tesla-V100-PCIE-16GB'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "filebase = gpu_name.replace(\" \", \"-\")\n",
    "filebase"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "folder = \"data\"\n",
    "os.makedirs(folder, exist_ok=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def factors_int(s1=100, s2=100):\n",
    "    a = np.random.randint(1, 5, (s1, s2), dtype=np.int16)\n",
    "    b = np.random.randint(1, 10, (s1, s2), dtype=np.int16)\n",
    "    return a, b\n",
    "\n",
    "def factors_float(s1=100, s2=100):\n",
    "    a = np.random.randn(s1, s2).astype(np.float32)\n",
    "    b = np.random.randn(s1, s2).astype(np.float32)\n",
    "    return a, b\n",
    "\n",
    "def factors_float3(s1=100, s2=100):\n",
    "    a = np.random.randn(s1, s2).astype(np.float32)\n",
    "    b = np.random.randn(s1, s2).astype(np.float32)\n",
    "    c = np.random.uniform(low=0, high=10, size=(s1,s2)).astype(np.float32)\n",
    "    return a, b, c\n",
    "\n",
    "def factors_float5(s1=100, s2=100):\n",
    "    a = np.random.randn(s1, s2).astype(np.float32)\n",
    "    b = np.random.randn(s1, s2).astype(np.float32)\n",
    "    c = np.random.uniform(low=0, high=10, size=(s1,s2)).astype(np.float32)\n",
    "    d = np.random.uniform(low=5, high=15, size=(s1,s2)).astype(np.float32)\n",
    "    e = np.random.uniform(low=0, high=30, size=(s1,s2)).astype(np.float32)\n",
    "    return a, b, c, d, e"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Checking data sizes in Gb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "18.6264515966177\n",
      "37.25290308892727\n"
     ]
    }
   ],
   "source": [
    "a, _ = factors_int(size_combinations[-1][0], size_combinations[-1][1])\n",
    "print(get_object_size(a, units=\"Gb\"))\n",
    "a, _ = factors_float(size_combinations[-1][0], size_combinations[-1][1])\n",
    "print(get_object_size(a, units=\"Gb\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Benchmark\n",
    "\n",
    "#### Integer matrix multiplication"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.04 µs ± 27.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n",
      "464 µs ± 17.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "1.9 µs ± 2.04 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n",
      "20.7 µs ± 111 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "1.37 ms ± 66 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "87.8 µs ± 18.2 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "\n",
      "215 µs ± 2.78 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "583 µs ± 13.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "215 µs ± 2.97 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "65.5 µs ± 532 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "4.63 ms ± 17.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "590 µs ± 1.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "\n",
      "91.4 ms ± 3.37 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "21 ms ± 396 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "88.1 ms ± 575 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "14.7 ms ± 718 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "150 ms ± 2.55 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "53.7 ms ± 330 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "\n",
      "895 ms ± 5.12 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "163 ms ± 7.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "933 ms ± 14 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "115 ms ± 655 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "1.44 s ± 49.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "521 ms ± 4.65 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "\n",
      "8.98 s ± 26.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "1.75 s ± 28.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "8.84 s ± 24.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "1.37 s ± 38.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "OOM for size (100000,100000)\n",
      "OOM for size (100000,100000)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "df = pd.DataFrame(columns=columns)\n",
    "operation = \"a*b\"\n",
    "for s1, s2 in size_combinations:\n",
    "    a, b = factors_int(s1, s2)\n",
    "    r1 = %timeit -o multiply(a,b)\n",
    "    r2 = %timeit -o ne_multiply(a,b)\n",
    "    r3 = %timeit -o multcpu(a,b)\n",
    "    r4 = %timeit -o multparal(a,b)\n",
    "    try:\n",
    "        r5 = %timeit -o multcuda(a,b)\n",
    "        clear_memory_all_gpus()\n",
    "    except CudaDriverError: # in case of Out Of Memory (OOM)\n",
    "        r5 = AttributeDict()\n",
    "        r5[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))\n",
    "    try:\n",
    "        r6 = %timeit -o pt_multiply(a,b)\n",
    "        clear_memory_all_gpus()\n",
    "    except RuntimeError: # in case of Out Of Memory (OOM)\n",
    "        r6 = AttributeDict()\n",
    "        r6[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))\n",
    "    print(\"\")\n",
    "    row = header + [type(a[0,0]), s1, s2, operation, r1.average, r2.average, r3.average, r4.average, r5.average, r6.average]\n",
    "    df.loc[len(df)] = row\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>n_processors</th>\n",
       "      <th>cpu_memory</th>\n",
       "      <th>gpu_name</th>\n",
       "      <th>gpu_memory</th>\n",
       "      <th>data_type</th>\n",
       "      <th>size1</th>\n",
       "      <th>size2</th>\n",
       "      <th>operation</th>\n",
       "      <th>numpy</th>\n",
       "      <th>numexpr</th>\n",
       "      <th>numba_cpu</th>\n",
       "      <th>numba_paral</th>\n",
       "      <th>numba_gpu</th>\n",
       "      <th>pytorch</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.int16'&gt;</td>\n",
       "      <td>100</td>\n",
       "      <td>100</td>\n",
       "      <td>a*b</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.000464</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.000021</td>\n",
       "      <td>0.00137052</td>\n",
       "      <td>8.77816e-05</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.int16'&gt;</td>\n",
       "      <td>1000</td>\n",
       "      <td>1000</td>\n",
       "      <td>a*b</td>\n",
       "      <td>0.000215</td>\n",
       "      <td>0.000583</td>\n",
       "      <td>0.000215</td>\n",
       "      <td>0.000065</td>\n",
       "      <td>0.00463451</td>\n",
       "      <td>0.000590458</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.int16'&gt;</td>\n",
       "      <td>10000</td>\n",
       "      <td>10000</td>\n",
       "      <td>a*b</td>\n",
       "      <td>0.091427</td>\n",
       "      <td>0.021019</td>\n",
       "      <td>0.088133</td>\n",
       "      <td>0.014701</td>\n",
       "      <td>0.150002</td>\n",
       "      <td>0.0537218</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.int16'&gt;</td>\n",
       "      <td>100000</td>\n",
       "      <td>10000</td>\n",
       "      <td>a*b</td>\n",
       "      <td>0.894855</td>\n",
       "      <td>0.163243</td>\n",
       "      <td>0.932832</td>\n",
       "      <td>0.115164</td>\n",
       "      <td>1.44249</td>\n",
       "      <td>0.520506</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.int16'&gt;</td>\n",
       "      <td>100000</td>\n",
       "      <td>100000</td>\n",
       "      <td>a*b</td>\n",
       "      <td>8.982922</td>\n",
       "      <td>1.751220</td>\n",
       "      <td>8.841003</td>\n",
       "      <td>1.366295</td>\n",
       "      <td>OOM</td>\n",
       "      <td>OOM</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  n_processors  cpu_memory              gpu_name  gpu_memory  \\\n",
       "0           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "1           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "2           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "3           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "4           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "\n",
       "               data_type   size1   size2 operation     numpy   numexpr  \\\n",
       "0  <class 'numpy.int16'>     100     100       a*b  0.000002  0.000464   \n",
       "1  <class 'numpy.int16'>    1000    1000       a*b  0.000215  0.000583   \n",
       "2  <class 'numpy.int16'>   10000   10000       a*b  0.091427  0.021019   \n",
       "3  <class 'numpy.int16'>  100000   10000       a*b  0.894855  0.163243   \n",
       "4  <class 'numpy.int16'>  100000  100000       a*b  8.982922  1.751220   \n",
       "\n",
       "   numba_cpu  numba_paral   numba_gpu      pytorch  \n",
       "0   0.000002     0.000021  0.00137052  8.77816e-05  \n",
       "1   0.000215     0.000065  0.00463451  0.000590458  \n",
       "2   0.088133     0.014701    0.150002    0.0537218  \n",
       "3   0.932832     0.115164     1.44249     0.520506  \n",
       "4   8.841003     1.366295         OOM          OOM  "
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "filename = filebase + \"_\" + operation + \"_int\" + \".csv\"\n",
    "df.to_csv(os.path.join(folder, filename), index=False)\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Float matrix multiplication"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.99 µs ± 22.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n",
      "455 µs ± 13.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "3.08 µs ± 5.05 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n",
      "21.7 µs ± 469 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "1.47 ms ± 3.31 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "84.9 µs ± 262 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "\n",
      "399 µs ± 3.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "551 µs ± 8.11 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "428 µs ± 2.23 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "92.8 µs ± 2.24 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "5.23 ms ± 117 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "952 µs ± 1.67 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "\n",
      "175 ms ± 1.29 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "31.5 ms ± 385 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "176 ms ± 504 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "30.8 ms ± 292 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "284 ms ± 37.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "101 ms ± 880 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "\n",
      "1.74 s ± 6.61 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "294 ms ± 8.62 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "1.74 s ± 11.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "289 ms ± 7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "2.83 s ± 5.55 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "930 ms ± 4.08 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "\n",
      "17.5 s ± 49.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "2.85 s ± 42.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "17.4 s ± 30.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "2.88 s ± 79.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "OOM for size (100000,100000)\n",
      "OOM for size (100000,100000)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "df = pd.DataFrame(columns=columns)\n",
    "operation = \"a*b\"\n",
    "for s1, s2 in size_combinations:\n",
    "    a, b = factors_float(s1, s2)\n",
    "    r1 = %timeit -o multiply(a,b)\n",
    "    r2 = %timeit -o ne_multiply(a,b)\n",
    "    r3 = %timeit -o multcpu(a,b)\n",
    "    r4 = %timeit -o multparal(a,b)\n",
    "    try:\n",
    "        r5 = %timeit -o multcuda(a,b)\n",
    "        clear_memory_all_gpus()\n",
    "    except: # in case of Out Of Memory (OOM)\n",
    "        r5 = AttributeDict()\n",
    "        r5[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))\n",
    "    try:\n",
    "        r6 = %timeit -o pt_multiply(a,b)\n",
    "        clear_memory_all_gpus()\n",
    "    except RuntimeError: # in case of Out Of Memory (OOM)\n",
    "        r6 = AttributeDict()\n",
    "        r6[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))\n",
    "    print(\"\")\n",
    "    row = header + [type(a[0,0]), s1, s2, operation, r1.average, r2.average, r3.average, r4.average, r5.average, r6.average]\n",
    "    df.loc[len(df)] = row"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>n_processors</th>\n",
       "      <th>cpu_memory</th>\n",
       "      <th>gpu_name</th>\n",
       "      <th>gpu_memory</th>\n",
       "      <th>data_type</th>\n",
       "      <th>size1</th>\n",
       "      <th>size2</th>\n",
       "      <th>operation</th>\n",
       "      <th>numpy</th>\n",
       "      <th>numexpr</th>\n",
       "      <th>numba_cpu</th>\n",
       "      <th>numba_paral</th>\n",
       "      <th>numba_gpu</th>\n",
       "      <th>pytorch</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100</td>\n",
       "      <td>100</td>\n",
       "      <td>a*b</td>\n",
       "      <td>0.000003</td>\n",
       "      <td>0.000455</td>\n",
       "      <td>0.000003</td>\n",
       "      <td>0.000022</td>\n",
       "      <td>0.00146891</td>\n",
       "      <td>8.48509e-05</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>1000</td>\n",
       "      <td>1000</td>\n",
       "      <td>a*b</td>\n",
       "      <td>0.000399</td>\n",
       "      <td>0.000551</td>\n",
       "      <td>0.000428</td>\n",
       "      <td>0.000093</td>\n",
       "      <td>0.00522768</td>\n",
       "      <td>0.00095236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>10000</td>\n",
       "      <td>10000</td>\n",
       "      <td>a*b</td>\n",
       "      <td>0.175345</td>\n",
       "      <td>0.031546</td>\n",
       "      <td>0.175785</td>\n",
       "      <td>0.030825</td>\n",
       "      <td>0.283723</td>\n",
       "      <td>0.100704</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100000</td>\n",
       "      <td>10000</td>\n",
       "      <td>a*b</td>\n",
       "      <td>1.735445</td>\n",
       "      <td>0.294421</td>\n",
       "      <td>1.740948</td>\n",
       "      <td>0.289153</td>\n",
       "      <td>2.82843</td>\n",
       "      <td>0.9301</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100000</td>\n",
       "      <td>100000</td>\n",
       "      <td>a*b</td>\n",
       "      <td>17.455325</td>\n",
       "      <td>2.847748</td>\n",
       "      <td>17.439472</td>\n",
       "      <td>2.878136</td>\n",
       "      <td>OOM</td>\n",
       "      <td>OOM</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  n_processors  cpu_memory              gpu_name  gpu_memory  \\\n",
       "0           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "1           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "2           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "3           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "4           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "\n",
       "                 data_type   size1   size2 operation      numpy   numexpr  \\\n",
       "0  <class 'numpy.float32'>     100     100       a*b   0.000003  0.000455   \n",
       "1  <class 'numpy.float32'>    1000    1000       a*b   0.000399  0.000551   \n",
       "2  <class 'numpy.float32'>   10000   10000       a*b   0.175345  0.031546   \n",
       "3  <class 'numpy.float32'>  100000   10000       a*b   1.735445  0.294421   \n",
       "4  <class 'numpy.float32'>  100000  100000       a*b  17.455325  2.847748   \n",
       "\n",
       "   numba_cpu  numba_paral   numba_gpu      pytorch  \n",
       "0   0.000003     0.000022  0.00146891  8.48509e-05  \n",
       "1   0.000428     0.000093  0.00522768   0.00095236  \n",
       "2   0.175785     0.030825    0.283723     0.100704  \n",
       "3   1.740948     0.289153     2.82843       0.9301  \n",
       "4  17.439472     2.878136         OOM          OOM  "
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "filename = filebase + \"_\" + operation + \"_float\" + \".csv\"\n",
    "df.to_csv(os.path.join(folder, filename), index=False)\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Exponential matrix multiplication"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "89.2 µs ± 214 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "463 µs ± 12.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "106 µs ± 98 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "31.2 µs ± 600 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "1.46 ms ± 3.63 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "103 µs ± 298 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "\n",
      "8.71 ms ± 5.59 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "844 µs ± 43.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "10.5 ms ± 43.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "523 µs ± 13.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "5.16 ms ± 32.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "969 µs ± 1.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "\n",
      "1 s ± 2.54 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "47.6 ms ± 514 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "1.15 s ± 769 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "51.4 ms ± 321 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "287 ms ± 34.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "103 ms ± 222 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "\n",
      "10 s ± 9.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "452 ms ± 3.82 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "11.5 s ± 10.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "506 ms ± 1.15 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "2.84 s ± 22.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "OOM for size (100000,10000)\n",
      "\n",
      "1min 40s ± 78.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "4.38 s ± 13.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "1min 54s ± 173 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "5.04 s ± 10.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "OOM for size (100000,100000)\n",
      "OOM for size (100000,100000)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "df = pd.DataFrame(columns=columns)\n",
    "operation = \"a*exp(b)\"\n",
    "for s1, s2 in size_combinations:\n",
    "    a, b = factors_float(s1, s2)\n",
    "    r1 = %timeit -o exponential(a,b)\n",
    "    r2 = %timeit -o ne_exponential(a,b)\n",
    "    r3 = %timeit -o expcpu(a,b)\n",
    "    r4 = %timeit -o expparal(a,b)\n",
    "    try:\n",
    "        r5 = %timeit -o expcuda(a,b)\n",
    "        clear_memory_all_gpus()\n",
    "    except: # in case of Out Of Memory (OOM)\n",
    "        r5 = AttributeDict()\n",
    "        r5[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2)) \n",
    "    try:\n",
    "        r6 = %timeit -o pt_exponential(a,b)\n",
    "        clear_memory_all_gpus()\n",
    "    except RuntimeError: # in case of Out Of Memory (OOM)\n",
    "        r6 = AttributeDict()\n",
    "        r6[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))\n",
    "    print(\"\")\n",
    "    row = header + [type(a[0,0]), s1, s2, operation, r1.average, r2.average, r3.average, r4.average, r5.average, r6.average]\n",
    "    df.loc[len(df)] = row"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>n_processors</th>\n",
       "      <th>cpu_memory</th>\n",
       "      <th>gpu_name</th>\n",
       "      <th>gpu_memory</th>\n",
       "      <th>data_type</th>\n",
       "      <th>size1</th>\n",
       "      <th>size2</th>\n",
       "      <th>operation</th>\n",
       "      <th>numpy</th>\n",
       "      <th>numexpr</th>\n",
       "      <th>numba_cpu</th>\n",
       "      <th>numba_paral</th>\n",
       "      <th>numba_gpu</th>\n",
       "      <th>pytorch</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100</td>\n",
       "      <td>100</td>\n",
       "      <td>a*exp(b)</td>\n",
       "      <td>0.000089</td>\n",
       "      <td>0.000463</td>\n",
       "      <td>0.000106</td>\n",
       "      <td>0.000031</td>\n",
       "      <td>0.00146372</td>\n",
       "      <td>0.000102519</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>1000</td>\n",
       "      <td>1000</td>\n",
       "      <td>a*exp(b)</td>\n",
       "      <td>0.008707</td>\n",
       "      <td>0.000844</td>\n",
       "      <td>0.010516</td>\n",
       "      <td>0.000523</td>\n",
       "      <td>0.00516015</td>\n",
       "      <td>0.000969088</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>10000</td>\n",
       "      <td>10000</td>\n",
       "      <td>a*exp(b)</td>\n",
       "      <td>1.001797</td>\n",
       "      <td>0.047643</td>\n",
       "      <td>1.145451</td>\n",
       "      <td>0.051389</td>\n",
       "      <td>0.286889</td>\n",
       "      <td>0.102657</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100000</td>\n",
       "      <td>10000</td>\n",
       "      <td>a*exp(b)</td>\n",
       "      <td>10.033744</td>\n",
       "      <td>0.452116</td>\n",
       "      <td>11.474779</td>\n",
       "      <td>0.505501</td>\n",
       "      <td>2.83925</td>\n",
       "      <td>OOM</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100000</td>\n",
       "      <td>100000</td>\n",
       "      <td>a*exp(b)</td>\n",
       "      <td>100.236637</td>\n",
       "      <td>4.384262</td>\n",
       "      <td>114.725856</td>\n",
       "      <td>5.042384</td>\n",
       "      <td>OOM</td>\n",
       "      <td>OOM</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  n_processors  cpu_memory              gpu_name  gpu_memory  \\\n",
       "0           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "1           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "2           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "3           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "4           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "\n",
       "                 data_type   size1   size2 operation       numpy   numexpr  \\\n",
       "0  <class 'numpy.float32'>     100     100  a*exp(b)    0.000089  0.000463   \n",
       "1  <class 'numpy.float32'>    1000    1000  a*exp(b)    0.008707  0.000844   \n",
       "2  <class 'numpy.float32'>   10000   10000  a*exp(b)    1.001797  0.047643   \n",
       "3  <class 'numpy.float32'>  100000   10000  a*exp(b)   10.033744  0.452116   \n",
       "4  <class 'numpy.float32'>  100000  100000  a*exp(b)  100.236637  4.384262   \n",
       "\n",
       "    numba_cpu  numba_paral   numba_gpu      pytorch  \n",
       "0    0.000106     0.000031  0.00146372  0.000102519  \n",
       "1    0.010516     0.000523  0.00516015  0.000969088  \n",
       "2    1.145451     0.051389    0.286889     0.102657  \n",
       "3   11.474779     0.505501     2.83925          OOM  \n",
       "4  114.725856     5.042384         OOM          OOM  "
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "filename = filebase + \"_\" + operation + \".csv\"\n",
    "df.to_csv(os.path.join(folder, filename), index=False)\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Sine matrix multiplication"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "83.2 µs ± 165 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "471 µs ± 9.66 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "99 µs ± 768 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "30.7 µs ± 651 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "1.45 ms ± 4.18 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "101 µs ± 901 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "\n",
      "8.51 ms ± 1.83 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "800 µs ± 10.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "10.8 ms ± 14.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "533 µs ± 9.21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "5.18 ms ± 60 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "966 µs ± 3.29 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "\n",
      "981 ms ± 1.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "45.7 ms ± 457 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "1.17 s ± 4.38 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "51.8 ms ± 375 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "286 ms ± 37.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "101 ms ± 521 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "\n",
      "9.93 s ± 37.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "427 ms ± 1.55 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "11.7 s ± 16.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "509 ms ± 3.85 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "2.83 s ± 5.39 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "OOM for size (100000,10000)\n",
      "\n",
      "1min 38s ± 49.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "4.19 s ± 19.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "1min 57s ± 93 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "5.08 s ± 13.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "OOM for size (100000,100000)\n",
      "OOM for size (100000,100000)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "df = pd.DataFrame(columns=columns)\n",
    "operation = \"a*sin(b)\"\n",
    "for s1, s2 in size_combinations:\n",
    "    a, b = factors_float(s1, s2)\n",
    "    r1 = %timeit -o sine(a,b)\n",
    "    r2 = %timeit -o ne_sine(a,b)\n",
    "    r3 = %timeit -o sincpu(a,b)\n",
    "    r4 = %timeit -o sinparal(a,b)\n",
    "    try:\n",
    "        r5 = %timeit -o sincuda(a,b)\n",
    "        clear_memory_all_gpus()\n",
    "    except: # in case of Out Of Memory (OOM)\n",
    "        r5 = AttributeDict()\n",
    "        r5[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))        \n",
    "    try:\n",
    "        r6 = %timeit -o pt_sine(a,b)\n",
    "        clear_memory_all_gpus()\n",
    "    except RuntimeError: # in case of Out Of Memory (OOM)\n",
    "        r6 = AttributeDict()\n",
    "        r6[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))\n",
    "    print(\"\")\n",
    "    row = header + [type(a[0,0]), s1, s2, operation, r1.average, r2.average, r3.average, r4.average, r5.average, r6.average]\n",
    "    df.loc[len(df)] = row"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>n_processors</th>\n",
       "      <th>cpu_memory</th>\n",
       "      <th>gpu_name</th>\n",
       "      <th>gpu_memory</th>\n",
       "      <th>data_type</th>\n",
       "      <th>size1</th>\n",
       "      <th>size2</th>\n",
       "      <th>operation</th>\n",
       "      <th>numpy</th>\n",
       "      <th>numexpr</th>\n",
       "      <th>numba_cpu</th>\n",
       "      <th>numba_paral</th>\n",
       "      <th>numba_gpu</th>\n",
       "      <th>pytorch</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100</td>\n",
       "      <td>100</td>\n",
       "      <td>a*sin(b)</td>\n",
       "      <td>0.000083</td>\n",
       "      <td>0.000471</td>\n",
       "      <td>0.000099</td>\n",
       "      <td>0.000031</td>\n",
       "      <td>0.00145325</td>\n",
       "      <td>0.000100636</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>1000</td>\n",
       "      <td>1000</td>\n",
       "      <td>a*sin(b)</td>\n",
       "      <td>0.008510</td>\n",
       "      <td>0.000800</td>\n",
       "      <td>0.010760</td>\n",
       "      <td>0.000533</td>\n",
       "      <td>0.00518061</td>\n",
       "      <td>0.000966255</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>10000</td>\n",
       "      <td>10000</td>\n",
       "      <td>a*sin(b)</td>\n",
       "      <td>0.981292</td>\n",
       "      <td>0.045746</td>\n",
       "      <td>1.174466</td>\n",
       "      <td>0.051767</td>\n",
       "      <td>0.286078</td>\n",
       "      <td>0.100841</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100000</td>\n",
       "      <td>10000</td>\n",
       "      <td>a*sin(b)</td>\n",
       "      <td>9.929282</td>\n",
       "      <td>0.427063</td>\n",
       "      <td>11.722498</td>\n",
       "      <td>0.509446</td>\n",
       "      <td>2.82914</td>\n",
       "      <td>OOM</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100000</td>\n",
       "      <td>100000</td>\n",
       "      <td>a*sin(b)</td>\n",
       "      <td>98.504510</td>\n",
       "      <td>4.186946</td>\n",
       "      <td>117.061011</td>\n",
       "      <td>5.078236</td>\n",
       "      <td>OOM</td>\n",
       "      <td>OOM</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  n_processors  cpu_memory              gpu_name  gpu_memory  \\\n",
       "0           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "1           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "2           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "3           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "4           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "\n",
       "                 data_type   size1   size2 operation      numpy   numexpr  \\\n",
       "0  <class 'numpy.float32'>     100     100  a*sin(b)   0.000083  0.000471   \n",
       "1  <class 'numpy.float32'>    1000    1000  a*sin(b)   0.008510  0.000800   \n",
       "2  <class 'numpy.float32'>   10000   10000  a*sin(b)   0.981292  0.045746   \n",
       "3  <class 'numpy.float32'>  100000   10000  a*sin(b)   9.929282  0.427063   \n",
       "4  <class 'numpy.float32'>  100000  100000  a*sin(b)  98.504510  4.186946   \n",
       "\n",
       "    numba_cpu  numba_paral   numba_gpu      pytorch  \n",
       "0    0.000099     0.000031  0.00145325  0.000100636  \n",
       "1    0.010760     0.000533  0.00518061  0.000966255  \n",
       "2    1.174466     0.051767    0.286078     0.100841  \n",
       "3   11.722498     0.509446     2.82914          OOM  \n",
       "4  117.061011     5.078236         OOM          OOM  "
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "filename = filebase + \"_\" + operation + \".csv\"\n",
    "df.to_csv(os.path.join(folder, filename), index=False)\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Multiple matrix multiplication (3 factors)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.DataFrame(columns=columns)\n",
    "operation = \"a*b*c\"\n",
    "for s1, s2 in size_combinations:\n",
    "    a, b, c = factors_float3(s1, s2)\n",
    "    r1 = %timeit -o multiply3(a,b,c)\n",
    "    r2 = %timeit -o ne_multiply3(a,b,c)\n",
    "    r3 = %timeit -o multfcpu3(a,b,c)\n",
    "    r4 = %timeit -o multfparal3(a,b,c)\n",
    "    try:\n",
    "        r5 = %timeit -o multfcuda3(a,b,c)\n",
    "        clear_memory_all_gpus()\n",
    "    except: # in case of Out Of Memory (OOM)\n",
    "        r5 = AttributeDict()\n",
    "        r5[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))\n",
    "    try:\n",
    "        r6 = %timeit -o pt_multiply3(a,b,c)\n",
    "        clear_memory_all_gpus()\n",
    "    except RuntimeError: # in case of Out Of Memory (OOM)\n",
    "        r6 = AttributeDict()\n",
    "        r6[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))\n",
    "    print(\"\")\n",
    "    row = header + [type(a[0,0]), s1, s2, operation, r1.average, r2.average, r3.average, r4.average, r5.average, r6.average]\n",
    "    df.loc[len(df)] = row"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "filename = filebase + \"_\" + operation + \".csv\"\n",
    "df.to_csv(os.path.join(folder, filename), index=False)\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Multiple matrix multiplication (5 factors)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.DataFrame(columns=columns)\n",
    "operation = \"a*b*c*d*e\"\n",
    "for s1, s2 in size_combinations:\n",
    "    a, b, c, d, e = factors_float5(s1, s2)\n",
    "    r1 = %timeit -o multiply5(a,b,c,d,e)\n",
    "    r2 = %timeit -o ne_multiply5(a,b,c,d,e)\n",
    "    r3 = %timeit -o multfcpu5(a,b,c,d,e)\n",
    "    r4 = %timeit -o multfparal5(a,b,c,d,e)\n",
    "    try:\n",
    "        r5 = %timeit -o multfcuda5(a,b,c,d,e)\n",
    "        clear_memory_all_gpus()\n",
    "    except: # in case of Out Of Memory (OOM)\n",
    "        r5 = AttributeDict()\n",
    "        r5[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))\n",
    "    try:\n",
    "        r6 = %timeit -o pt_multiply5(a,b,c,d,e)\n",
    "        clear_memory_all_gpus()\n",
    "    except RuntimeError: # in case of Out Of Memory (OOM)\n",
    "        r6 = AttributeDict()\n",
    "        r6[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))\n",
    "    print(\"\")\n",
    "    row = header + [type(a[0,0]), s1, s2, operation, r1.average, r2.average, r3.average, r4.average, r5.average, r6.average]\n",
    "    df.loc[len(df)] = row"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "filename = filebase + \"_\" + operation + \".csv\"\n",
    "df.to_csv(os.path.join(folder, filename), index=False)\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Exponential sine matrix multiplication"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "215 µs ± 740 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "477 µs ± 15 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "247 µs ± 2.07 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "44.9 µs ± 917 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "1.99 ms ± 12 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "174 µs ± 13.3 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "\n",
      "21.4 ms ± 34.9 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "1.37 ms ± 14.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "24.5 ms ± 41 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "1.16 ms ± 22.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "7.35 ms ± 286 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "1.46 ms ± 5.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "\n",
      "2.38 s ± 2.54 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "100 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "2.58 s ± 7.91 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "113 ms ± 221 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "356 ms ± 40.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "149 ms ± 1.15 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "\n",
      "23.8 s ± 18.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "1.02 s ± 13.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "25.8 s ± 15.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "1.12 s ± 4.75 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "OOM for size (100000,10000)\n",
      "OOM for size (100000,10000)\n",
      "\n",
      "3min 58s ± 105 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "9.86 s ± 94.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "4min 18s ± 2.77 s per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "11.2 s ± 7.94 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "OOM for size (100000,100000)\n",
      "OOM for size (100000,100000)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "df = pd.DataFrame(columns=columns)\n",
    "operation = \"a*exp(b)*sin(c)\"\n",
    "for s1, s2 in size_combinations:\n",
    "    a, b, c = factors_float3(s1, s2)\n",
    "    r1 = %timeit -o exponential_sine(a,b,c)\n",
    "    r2 = %timeit -o ne_exponential_sine(a,b,c)\n",
    "    r3 = %timeit -o expsincpu(a,b,c)\n",
    "    r4 = %timeit -o expsinparal(a,b,c)\n",
    "    try:\n",
    "        r5 = %timeit -o expsincuda(a,b,c)\n",
    "        clear_memory_all_gpus()\n",
    "    except: # in case of Out Of Memory (OOM)\n",
    "        r5 = AttributeDict()\n",
    "        r5[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))        \n",
    "    try:\n",
    "        r6 = %timeit -o pt_exponential_sine(a,b,c)\n",
    "        clear_memory_all_gpus()\n",
    "    except RuntimeError: # in case of Out Of Memory (OOM)\n",
    "        r6 = AttributeDict()\n",
    "        r6[\"average\"] = \"OOM\"\n",
    "        print(\"OOM for size ({},{})\".format(s1, s2))\n",
    "    print(\"\")\n",
    "    row = header + [type(a[0,0]), s1, s2, operation, r1.average, r2.average, r3.average, r4.average, r5.average, r6.average]\n",
    "    df.loc[len(df)] = row"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>n_processors</th>\n",
       "      <th>cpu_memory</th>\n",
       "      <th>gpu_name</th>\n",
       "      <th>gpu_memory</th>\n",
       "      <th>data_type</th>\n",
       "      <th>size1</th>\n",
       "      <th>size2</th>\n",
       "      <th>operation</th>\n",
       "      <th>numpy</th>\n",
       "      <th>numexpr</th>\n",
       "      <th>numba_cpu</th>\n",
       "      <th>numba_paral</th>\n",
       "      <th>numba_gpu</th>\n",
       "      <th>pytorch</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100</td>\n",
       "      <td>100</td>\n",
       "      <td>a*exp(b)*sin(c)</td>\n",
       "      <td>0.000215</td>\n",
       "      <td>0.000477</td>\n",
       "      <td>0.000247</td>\n",
       "      <td>0.000045</td>\n",
       "      <td>0.00198992</td>\n",
       "      <td>0.00017382</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>1000</td>\n",
       "      <td>1000</td>\n",
       "      <td>a*exp(b)*sin(c)</td>\n",
       "      <td>0.021384</td>\n",
       "      <td>0.001372</td>\n",
       "      <td>0.024456</td>\n",
       "      <td>0.001157</td>\n",
       "      <td>0.00735039</td>\n",
       "      <td>0.00146446</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>10000</td>\n",
       "      <td>10000</td>\n",
       "      <td>a*exp(b)*sin(c)</td>\n",
       "      <td>2.383109</td>\n",
       "      <td>0.100398</td>\n",
       "      <td>2.577221</td>\n",
       "      <td>0.112853</td>\n",
       "      <td>0.355643</td>\n",
       "      <td>0.149033</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100000</td>\n",
       "      <td>10000</td>\n",
       "      <td>a*exp(b)*sin(c)</td>\n",
       "      <td>23.818136</td>\n",
       "      <td>1.019712</td>\n",
       "      <td>25.803186</td>\n",
       "      <td>1.120956</td>\n",
       "      <td>OOM</td>\n",
       "      <td>OOM</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>24</td>\n",
       "      <td>440.909752</td>\n",
       "      <td>Tesla V100-PCIE-16GB</td>\n",
       "      <td>15.781738</td>\n",
       "      <td>&lt;class 'numpy.float32'&gt;</td>\n",
       "      <td>100000</td>\n",
       "      <td>100000</td>\n",
       "      <td>a*exp(b)*sin(c)</td>\n",
       "      <td>238.690387</td>\n",
       "      <td>9.864431</td>\n",
       "      <td>258.552602</td>\n",
       "      <td>11.205123</td>\n",
       "      <td>OOM</td>\n",
       "      <td>OOM</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  n_processors  cpu_memory              gpu_name  gpu_memory  \\\n",
       "0           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "1           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "2           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "3           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "4           24  440.909752  Tesla V100-PCIE-16GB   15.781738   \n",
       "\n",
       "                 data_type   size1   size2        operation       numpy  \\\n",
       "0  <class 'numpy.float32'>     100     100  a*exp(b)*sin(c)    0.000215   \n",
       "1  <class 'numpy.float32'>    1000    1000  a*exp(b)*sin(c)    0.021384   \n",
       "2  <class 'numpy.float32'>   10000   10000  a*exp(b)*sin(c)    2.383109   \n",
       "3  <class 'numpy.float32'>  100000   10000  a*exp(b)*sin(c)   23.818136   \n",
       "4  <class 'numpy.float32'>  100000  100000  a*exp(b)*sin(c)  238.690387   \n",
       "\n",
       "    numexpr   numba_cpu  numba_paral   numba_gpu     pytorch  \n",
       "0  0.000477    0.000247     0.000045  0.00198992  0.00017382  \n",
       "1  0.001372    0.024456     0.001157  0.00735039  0.00146446  \n",
       "2  0.100398    2.577221     0.112853    0.355643    0.149033  \n",
       "3  1.019712   25.803186     1.120956         OOM         OOM  \n",
       "4  9.864431  258.552602    11.205123         OOM         OOM  "
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "filename = filebase + \"_\" + operation + \".csv\"\n",
    "df.to_csv(os.path.join(folder, filename), index=False)\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python (benchmark)",
   "language": "python",
   "name": "benchmark"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
